/* 
 * jxListFiles Project (2012, 2013, 2014)
 * 
 * by Denilson Edinaldo Pinto
 * 
 * GPL
 * Copyright (C) 2014
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package org.jxListFiles.view;

import java.awt.BorderLayout;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.DefaultListModel;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JSplitPane;
import javax.swing.JToolBar;
import javax.swing.JViewport;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;

import org.jxListFiles.RunJxListFiles;
import org.jxListFiles.i18n.I18N;
import org.jxListFiles.model.MyFile;
import org.jxListFiles.model.Project;
import org.jxSwing.component.button.FindButton;
import org.jxSwing.component.button.NewButton;
import org.jxSwing.component.button.RefreshButton;
import org.jxSwing.component.button.SaveButton;
import org.jxSwing.component.chooser.DirectoryChooser;
import org.jxSwing.component.frame.Frame;
import org.jxSwing.component.panel.BeanTablePanel;
import org.jxUtils.check.CheckUtil;
import org.jxUtils.collection.CollectionUtil;
import org.jxUtils.file.FileSize;
import org.jxUtils.file.FilesList;
import org.jxUtils.file.SearchFiles;
import org.jxUtils.lang.StringUtil;

/**
 * @author Denilson Edinaldo Pinto
 * @porject jxListFiles
 * @package org.jxListFiles.view
 * @date 07/04/2012 - 13:17:34
 */
public final class InitFrame extends Frame {
	
	private static final long serialVersionUID = -4176584058067149909L;
	
	private JToolBar toolBar;
	
	private NewButton btnNew;
	
	private SaveButton btnSave;
	
	private RefreshButton btnRefresh;
	
	private JSeparator separator1;
	
	private FindButton btnFindDuplicate;
	
	private JSplitPane spltpn;
	
	private JScrollPane scrlpnProjects;
	
	private JList<Project> lstProjects;
	
	private BeanTablePanel<MyFile> tablePanel;
	
	private Project project = null;
	
	/**
	 * This is the default constructor
	 */
	public InitFrame() {
	
		initGUI();
	}
	
	private void initGUI() {
	
		setTitle("jxListFiles - v3.1.0");
		setIconImage(Toolkit.getDefaultToolkit().getImage(InitFrame.class.getResource("/org/jxListFiles/resource/jxListFiles.png")));
		setSize(800, 500);
		
		getContentPane().setLayout(new BorderLayout());
		getContentPane().add(getToolBar(), BorderLayout.NORTH);
		getContentPane().add(getSpltpn(), BorderLayout.CENTER);
		
		File[] projects = RunJxListFiles.getDataDir().listFiles();
		
		CollectionUtil.sort(projects);
		
		// 
		for(File file : projects) {
			
			// 
			if(!file.isHidden() && file.isFile()) {
				
				// 
				try (ObjectInputStream stream = new ObjectInputStream(new FileInputStream(file))) {
					
					getListModel().addElement((Project)stream.readObject());
					
				}catch(IOException | ClassNotFoundException exception) {
					
					// TODO: Implementar Tratamento de Erro
					exception.printStackTrace();
				}
			}
		}
		
		setLocationRelativeTo(null);
		setExtendedState(MAXIMIZED_BOTH);
		setVisible(true);
	}
	
	public JToolBar getToolBar() {
	
		if(toolBar == null) {
			toolBar = new JToolBar();
			toolBar.setBounds(new Rectangle(5, 5, 5, 5));
			toolBar.setFloatable(false);
			toolBar.add(getBtnNew());
			toolBar.add(getBtnSave());
			toolBar.add(getBtnRefresh());
			toolBar.add(getSeparator1());
			toolBar.add(getBtnFindDuplicate());
		}
		return toolBar;
	}
	
	public NewButton getBtnNew() {
	
		if(btnNew == null) {
			btnNew = new NewButton();
			btnNew.setToolTipText(I18N.messages().newProject());
			btnNew.setSize(new Dimension(40, 40));
			btnNew.addActionListener(new ActionListener() {
				
				public void actionPerformed(ActionEvent actionEvent) {
				
					// TODO: Implementar Internacionalização
					final String projectName = JOptionPane.showInputDialog("Nome do Projeto:");
					
					// 
					if(CheckUtil.isNotNullAndNotAbsoluteEmpty(projectName)) {
						
						// 
						if(getListModel().contains(new Project(projectName, null, null))) {
							
							// TODO: Implementar Internacionalização
							JOptionPane.showMessageDialog(null, "O Projeto '" + projectName.trim() + "' já existe.");
							
							return;
						}
						
						// 
						new VwTypeFilter() {
							
							private static final long serialVersionUID = -4183968239920061531L;
							
							@Override
							public void find() {
								
								final DirectoryChooser directoryChooser = new DirectoryChooser();
								
								// TODO: Implementar Internacionalização
								directoryChooser.setDialogTitle("Selecione um Diretório");
								directoryChooser.setMultiSelectionEnabled(false);
								
								// 
								if(directoryChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
									
									analyzeDirectory(new Project(projectName, directoryChooser.getSelectedFile(), getExtensions()));
								}
							}
						};
					}
				}
			});
		}
		return btnNew;
	}
	
	public SaveButton getBtnSave() {
	
		if(btnSave == null) {
			btnSave = new SaveButton();
			btnSave.setEnabled(false);
			// TODO: Implementar Internacionalização
			btnSave.setToolTipText("Salvar Projeto");
			btnSave.setSize(new Dimension(40, 40));
			btnSave.addActionListener(new ActionListener() {
				
				public void actionPerformed(ActionEvent actionEvent) {
				
					// 
					try (ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream(new File(RunJxListFiles.getDataDir(), project.getName())))) {
						
						project.setValues(getTablePanel().getBeanTable().getRows());
						
						stream.writeObject(project);
						
						getListModel().removeElement(project); // Exclui o Projeto antigo (caso exista)
						getListModel().addElement(project); 
						
						getLstProjects().repaint();
						
					}catch(IOException ioException) {
						
						// TODO: Implementar Tratamento de Erro
						ioException.printStackTrace();
					}
				}
			});
		}
		return btnSave;
	}
	
	public RefreshButton getBtnRefresh() {
	
		if(btnRefresh == null) {
			btnRefresh = new RefreshButton();
			btnRefresh.setEnabled(false);
			// TODO: Implementar Internacionalização
			btnRefresh.setToolTipText("Atualizar Lista");
			btnRefresh.setSize(new Dimension(40, 40));
			btnRefresh.addActionListener(new ActionListener() {
				
				public void actionPerformed(ActionEvent actionEvent) {
				
					analyzeDirectory(project);
				}
			});
		}
		return btnRefresh;
	}
	
	public JSeparator getSeparator1() {
	
		if(separator1 == null) {
			separator1 = new JSeparator();
			separator1.setPreferredSize(new Dimension(2, 35));
			separator1.setOrientation(SwingConstants.VERTICAL);
		}
		return separator1;
	}
	
	public FindButton getBtnFindDuplicate() {
	
		if(btnFindDuplicate == null) {
			btnFindDuplicate = new FindButton();
			btnFindDuplicate.setEnabled(false);
			// TODO: Implementar Internacionalização
			btnFindDuplicate.setToolTipText("Procurar Duplicados");
			btnFindDuplicate.setSize(new Dimension(40, 40));
			btnFindDuplicate.addActionListener(new ActionListener() {
				
				public void actionPerformed(ActionEvent actionEvent) {
				
					Map<String, List<MyFile>> duplicates = new HashMap<>();
					
					// 
					for(MyFile myFile : tablePanel.getRows()) {
						
						// 
						String name = myFile.getName();
						
						name = name.substring(0, name.lastIndexOf(".")); // Remove a extensão do arquivo
						name = StringUtil.normalize(name); // Remove os acentos e outros caracteres especiais (Normaliza a String)
						name = StringUtil.removeSpace(name); // Remove espaços => [ \t\n\x0B\f\r]
						name = StringUtil.removePunctuation(name); // Remove pontuação => !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
						name = name.toUpperCase(); // Converte para MAIUSCULO
						
						// 
						if( !duplicates.keySet().contains(name)) {
							
							duplicates.put(name, new ArrayList<MyFile>(Arrays.asList(new MyFile[]{myFile})));
							
						}else {
							
							duplicates.get(name).add(myFile);
						}
					}
					
					// 
					StringBuilder filter = new StringBuilder();
					
					// 
					for(String key : duplicates.keySet()) {
						
						List<MyFile> list = duplicates.get(key);
						
						// 
						if(list.size() > 1) {
							
							// 
							for(MyFile myFile : list) {
								
								// 
								if(filter.length() > 0) {
									
									filter.append("|");
								}
								
								filter.append(myFile.getName());
							}
						}
					}
					
					// Se existem Arquivos Duplicados, aplica o filtro
					if(filter.length() > 0) {
						
						getTablePanel().filter(filter.toString(), false);
					}
				}
			});
		}
		return btnFindDuplicate;
	}
	
	public JSplitPane getSpltpn() {
	
		if(spltpn == null) {
			spltpn = new JSplitPane();
			spltpn.setOneTouchExpandable(true);
			spltpn.setDividerLocation(250);
			spltpn.setRightComponent(getTablePanel());
			spltpn.setLeftComponent(getScrlpnProjects());
		}
		return spltpn;
	}
	
	public JScrollPane getScrlpnProjects() {
	
		if(scrlpnProjects == null) {
			scrlpnProjects = new JScrollPane();
			
			JViewport vwprtProjects = new JViewport();
			// TODO: Implementar Internacionalização
			JLabel lblProjects = new JLabel("Projetos", SwingConstants.CENTER);
			lblProjects.setFont(new Font(lblProjects.getFont().getName(), Font.BOLD, lblProjects.getFont().getSize()));
			lblProjects.setPreferredSize(new Dimension(250, 30));
			vwprtProjects.setView(lblProjects);
			
			scrlpnProjects.setColumnHeader(vwprtProjects);
			scrlpnProjects.setViewportView(getLstProjects());
		}
		return scrlpnProjects;
	}
	
	public JList<Project> getLstProjects() {
	
		if(lstProjects == null) {
			lstProjects = new JList<>(new DefaultListModel<Project>());
			lstProjects.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
			lstProjects.addMouseListener(new ListAction(lstProjects));
		}
		return lstProjects;
	}
	
	public BeanTablePanel<MyFile> getTablePanel() {
	
		if(tablePanel == null) {
			tablePanel = new BeanTablePanel<MyFile>(MyFile.class);
			tablePanel.locked();
			tablePanel.enabledTools(false);
			tablePanel.getBeanTable().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
			tablePanel.getColumnModel().getColumn(0).setMinWidth(150);
			tablePanel.getColumnModel().getColumn(1).setMinWidth(150);
			tablePanel.getColumnModel().getColumn(1).setMaxWidth(150);
			tablePanel.getColumnModel().getColumn(2).setMinWidth(100);
			tablePanel.getColumnModel().getColumn(2).setMaxWidth(100);
			tablePanel.getBeanTable().addMouseListener(new TableAction(tablePanel));
		}
		return tablePanel;
	}
	
	/**
	 * @return List Model
	 */
	public DefaultListModel<Project> getListModel() {
	
		return((DefaultListModel<Project>)getLstProjects().getModel());
	}

	/**
	 * @param project
	 */
	private void analyzeDirectory(final Project project) {
	
		this.project = project;
		this.project.setDate(new Date());
		
		// Limpa a Tabela
		getTablePanel().removeAllRows();
		
		// TODO: Implementar Internacionalização
		final VwWait vwWait = new VwWait("Procurando Arquivos...");
		
		//
		new Thread(new Runnable() {
			
			@Override
			public void run() {
			
				vwWait.setVisible(true);
			}
		}).start();
		
		//
		new Thread(new Runnable() {
			
			@Override
			public void run() {
			
				try {
					//
					FilesList filesList = new FilesList();
					
					SearchFiles searchFiles = new SearchFiles();
					
					searchFiles.search(project.getDirectory(), filesList, project.getExtensions());
					
					// 
					getTablePanel().setRows(MyFile.toMyFileList(filesList.getFilesList()));
					
					getTablePanel().sorter(0);
					
					vwWait.dispose();
					
					//
					if(getTablePanel().getRowCount() > 0) {
						
						getTablePanel().setTitle(project.getName());
						
						getBtnSave().setEnabled(true);
						getBtnRefresh().setEnabled(true);
						getBtnFindDuplicate().setEnabled(true);
						getTablePanel().enabledTools(true);
						
					}else {
						
						// TODO: Implementar Internacionalização
						JOptionPane.showMessageDialog(null, "Nenhum Arquivo foi encontrado para o Filtro marcado.");
					}
					
				}catch(IOException ioException) {
					
					// TODO: Implementar Tratamento de Erro
					ioException.printStackTrace();
				}
			}
		}).start();
	}
	
	/**
	 * 
	 * @author Denilson Edinaldo Pinto
	 * @porject jxListFiles
	 * @package org.jxListFiles.view
	 * @date 22/04/2014 - 15:20:17
	 *
	 */
	private class ListAction extends MouseAdapter {
		
		private final JPopupMenu menu;
		
		/**
		 * @param listProjects
		 */
		public ListAction(final JList<Project> listProjects) {
		
			menu = new JPopupMenu();
			
			// TODO: Implementar Internacionalização
			JMenuItem mniRename = new JMenuItem("Renomear");
			mniRename.addActionListener(new ActionListener() {
				
				@Override
				public void actionPerformed(ActionEvent actionEvent) {
				
					// 
					menu.setVisible(false);
					
					// TODO: Implementar Internacionalização
					if(JOptionPane.showConfirmDialog(null, "Deseja realmente Renomear o Projeto ?") == JOptionPane.YES_OPTION) {
						
						// TODO: Implementar Internacionalização
						String newName = JOptionPane.showInputDialog("Informe o novo nome:");
						
						// Se um novo Nome foi informado
						if(newName != null && !(newName = newName.trim()).isEmpty()) {
							
							try {
								// 
								Project project = listProjects.getSelectedValue();
								
								File file = new File(RunJxListFiles.getDataDir(), project.getName());
								File fileDest = new File(RunJxListFiles.getDataDir(), newName);
								
								// Tenta renomear o Projeto
								file.renameTo(fileDest);
								
								project.setName(newName);
								
								listProjects.repaint();
								
							}catch(Throwable throwable) {
								
								// TODO: Implementar Tratamento de Erro
								throwable.printStackTrace();
							}
						}
					}
				}
			});
			
			// TODO: Implementar Internacionalização
			JMenuItem mniDelete = new JMenuItem("Excluir");
			mniDelete.addActionListener(new ActionListener() {
				
				@Override
				public void actionPerformed(ActionEvent actionEvent) {
				
					// 
					menu.setVisible(false);
					
					// TODO: Implementar Internacionalização
					if(JOptionPane.showConfirmDialog(null, "Deseja realmente Excluir o Projeto ?") == JOptionPane.YES_OPTION) {
						
						Project projectAux = listProjects.getSelectedValue();
						
						try {
							// 
							File file = new File(RunJxListFiles.getDataDir(), projectAux.getName());
							
							getListModel().removeElement(projectAux);
							listProjects.repaint();
							
							// 
							if(projectAux.equals(project) && !getTablePanel().isEmpty()) {
								
								getTablePanel().removeAllRows();
							}
							
							// 
							if(!file.delete()) {
								
								getListModel().addElement(project);
								listProjects.repaint();
							}
							
						}catch(Throwable throwable) {
							
							// TODO: Implementar Tratamento de Erro
							throwable.printStackTrace();
							
							getListModel().addElement(project);
							listProjects.repaint();
						}
					}
				}
			});
			
			// 
			menu.add(mniRename);
			menu.addSeparator();
			menu.add(mniDelete);
		}
		
		@Override
		public void mouseClicked(MouseEvent mouseEvent) {
		
			// 
			menu.setVisible(false);
			
			// Abre o Arquivo
			if(mouseEvent.getClickCount() == 2) {
				
				// 
				new Thread(new Runnable() {
					
					@Override
					public void run() {
					
						Project projectAux = lstProjects.getSelectedValue();
						
						// 
						try (ObjectInputStream stream = new ObjectInputStream(new FileInputStream(new File(RunJxListFiles.getDataDir(), projectAux.getName())))) {
							
							project = (Project)stream.readObject();
							
							getTablePanel().setRows(project.getValues());
							getTablePanel().setTitle(project.getName());
							
							getBtnSave().setEnabled(true);
							getBtnRefresh().setEnabled(true);
							getBtnFindDuplicate().setEnabled(true);
							getTablePanel().enabledTools(true);
							
						}catch(IOException | ClassNotFoundException exception) {
							
							// TODO: Implementar Tratamento de Erro
							exception.printStackTrace();
						}
					}
				}).start();
				
			}else if(mouseEvent.getButton() == MouseEvent.BUTTON3) {
				
				lstProjects.setSelectedIndex(lstProjects.locationToIndex(mouseEvent.getPoint()));
				
				menu.setLocation(mouseEvent.getXOnScreen(), mouseEvent.getYOnScreen());
				menu.setVisible(true);
			}
		}
	}
	
	/**
	 * @author Denilson Edinaldo Pinto
	 * @porject jxListFiles
	 * @package org.jxListFiles.view
	 * @date 15/04/2014 - 10:13:46
	 */
	private class TableAction extends MouseAdapter {
		
		private BeanTablePanel<MyFile> tablePanel;
		
		private final JPopupMenu menu;
		
		/**
		 * @param tablePanel
		 */
		public TableAction(final BeanTablePanel<MyFile> tablePanel) {
		
			this.tablePanel = tablePanel;
			
			menu = new JPopupMenu();
			
			// TODO: Implementar Internacionalização
			JMenuItem mniOpenDir = new JMenuItem("Abrir o Diretório");
			mniOpenDir.addActionListener(new ActionListener() {
				
				@Override
				public void actionPerformed(ActionEvent actionEvent) {
				
					menu.setVisible(false);
					
					// 
					new Thread(new Runnable() {
						
						@Override
						public void run() {
						
							try {
								// 
								MyFile myFile = tablePanel.getSelectedBean();
								
								Desktop.getDesktop().open(new File(myFile.getDirectory()));
								
							}catch(Throwable throwable) {
								
								// TODO: Implementar Tratamento de Erro
								throwable.printStackTrace();
							}
						}
					}).start();
				}
			});
			
			// TODO: Implementar Internacionalização
			JMenuItem mniRemove = new JMenuItem("Remover da Lista");
			mniRemove.addActionListener(new ActionListener() {
				
				@Override
				public void actionPerformed(ActionEvent actionEvent) {
				
					menu.setVisible(false);
					
					// TODO: Implementar Internacionalização
					if(JOptionPane.showConfirmDialog(null, "Deseja realmente Remover o Arquivo da Lista ?") == JOptionPane.YES_OPTION) {
						
						try {
							// 
							MyFile myFile = tablePanel.getSelectedBean();
							 
							tablePanel.removeRow(myFile);
							
							tablePanel.repaint();
							
						}catch(Throwable throwable) {
							
							// TODO: Implementar Tratamento de Erro
							throwable.printStackTrace();
						}
					}
				}
			});
			
			// TODO: Implementar Internacionalização
			JMenuItem mniRename = new JMenuItem("Renomear");
			mniRename.addActionListener(new ActionListener() {
				
				@Override
				public void actionPerformed(ActionEvent actionEvent) {
				
					menu.setVisible(false);
					
					// TODO: Implementar Internacionalização
					if(JOptionPane.showConfirmDialog(null, "Deseja realmente Renomear o Arquivo ?") == JOptionPane.YES_OPTION) {
						
						// 
						MyFile myFile = tablePanel.getSelectedBean();
						
						// TODO: Implementar Internacionalização
						String newName = JOptionPane.showInputDialog("Informe o novo nome:", myFile.getName());
						
						// Se um novo Nome foi informado
						if(newName != null && !(newName = newName.trim()).isEmpty()) {
							
							try {
								// 
								newName = newName + myFile.getName().substring(myFile.getName().lastIndexOf("."));
								
								File file = new File(myFile.getDirectory(), myFile.getName());
								File fileDest = new File(myFile.getDirectory(), newName);
								
								// Tenta renomear o Arquivo
								file.renameTo(fileDest);
								
								// 
								myFile.setName(fileDest.getName());
								myFile.setSize(new FileSize(fileDest.length()));
								myFile.setLastModification(new Date(fileDest.lastModified()));
								
								tablePanel.repaint();
								
							}catch(Throwable throwable) {
								
								// TODO: Implementar Tratamento de Erro
								throwable.printStackTrace();
							}
						}
					}
				}
			});
			
			// TODO: Implementar Internacionalização
			JMenuItem mniDelete = new JMenuItem("Excluir");
			mniDelete.addActionListener(new ActionListener() {
				
				@Override
				public void actionPerformed(ActionEvent actionEvent) {
				
					menu.setVisible(false);
					
					// TODO: Implementar Internacionalização
					if(JOptionPane.showConfirmDialog(null, "Deseja realmente Excluir o Arquivo ?") == JOptionPane.YES_OPTION) {
						
						try {
							// 
							MyFile myFile = tablePanel.getSelectedBean();
							
							File file = new File(myFile.getDirectory(), myFile.getName());
							
							// Tenta excluir o Arquivo
							file.delete();
							
							// 
							tablePanel.removeRow(myFile);
							
							tablePanel.repaint();
							
						}catch(Throwable throwable) {
							
							// TODO: Implementar Tratamento de Erro
							throwable.printStackTrace();
						}
					}
				}
			});
			
			menu.add(mniRemove);
			menu.addSeparator();
			menu.add(mniOpenDir);
			menu.addSeparator();
			menu.add(mniRename);
			menu.addSeparator();
			menu.add(mniDelete);
		}
		
		@Override
		public void mouseClicked(MouseEvent mouseEvent) {
		
			menu.setVisible(false);
			
			// Abre o Arquivo
			if(mouseEvent.getClickCount() == 2) {
				
				// 
				new Thread(new Runnable() {
					
					@Override
					public void run() {
					
						try {
							// 
							MyFile myFile = tablePanel.getSelectedBean();
							
							File file = new File(myFile.getDirectory(), myFile.getName());
							
							Desktop.getDesktop().open(file);
							
						}catch(Throwable throwable) {
							
							// TODO: Implementar Tratamento de Erro
							throwable.printStackTrace();
						}
					}
				}).start();
				
			}else if(mouseEvent.getButton() == MouseEvent.BUTTON3) {
				
				tablePanel.setSelectedRow(tablePanel.rowAtPoint(mouseEvent.getPoint()));
				
				menu.setLocation(mouseEvent.getXOnScreen(), mouseEvent.getYOnScreen());
				menu.setVisible(true);
			}
		}
	}
}